package com.qiyuesuo.server.servlet;

import com.qiyuesuo.server.dao.FileInfoDao;
import com.qiyuesuo.server.PO.FileInfo;
import com.qiyuesuo.server.util.AES.AESUtils;
import com.qiyuesuo.server.util.RSA.RSAUtil;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 上传文件
 * 从client端的流，加密到本地文件输出流
 * AES加密文件，再用RSA的公钥加密AES的密钥，这样有私钥的客户端就可以解密文件
 *
 * @author s77
 * @create 2020-4月-01 14:56
 */
public class UploadServlet extends HttpServlet {
    private final static Logger logger = LoggerFactory.getLogger(UploadServlet.class);

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //加密
        //生成AES对称密钥，读取RSA公钥
        String secretKey = null;
        try {
            secretKey = AESUtils.getSecretKey();
            System.err.println(secretKey);
        } catch (Exception e) {
            logger.error("获取AES密钥失败", e);
        }
        String publicKey = "";
        InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("publicKey.txt");
        try (Scanner scanner = new Scanner(is)) {
            while (scanner.hasNextLine()) {
                publicKey += scanner.nextLine();
            }
        } catch (Exception e) {
            logger.error("读取公钥文件失败", e);
        }
        //设置请求和响应的编码格式
        req.setCharacterEncoding("GBK");
        resp.setCharacterEncoding("UTF-8");
        //file-upload
        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload fileUpload = new ServletFileUpload(factory);

        //判断是否是muitipart/form-data类型
        if (!ServletFileUpload.isMultipartContent(req)) {
            resp.getWriter().println("error");
        }
        //设置单个文件上传大小 5M //设置总上传文件大小 10M
        fileUpload.setFileSizeMax(5 * 1024 * 1024);
        fileUpload.setSizeMax(10 * 1024 * 1024);
        //解析请求
        try {
            List<FileItem> parseRequest = fileUpload.parseRequest(req);
            //获取数据
            for (FileItem fileItem : parseRequest) {
                //判断数据类型是不是普通的form表单字段
                if (!fileItem.isFormField()) {
                    //上传文件，按日期生成文件夹，AES加密
                    String fileName = fileItem.getName();
                    long size = fileItem.getSize();
                    String type = fileItem.getContentType();
                    logger.info(fileName + " -- 读取上传文件");
                    InputStream fileStream = fileItem.getInputStream();
                    Date date = new Date();
                    String dateForm = new SimpleDateFormat("yyyyMMdd").format(date);
                    String path = "D:/qiyuesuo/upload/" + dateForm;
                    //UUID文件重命名，避免文件重名
                    String realFileName = UUID.randomUUID().toString().replaceAll("-", "");
                    //保存文件
                    File file = new File(path, realFileName);
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }
                    logger.info(realFileName + " -- 文件内容加密写入");
                    OutputStream out = new FileOutputStream(file);
                    try {
                        //使用AES流加密方法，从请求的输入流加密到文件输出流
                        AESUtils.encryptStream(secretKey, fileStream, out);
                    } catch (Exception e) {
                        logger.error("文件加密写入失败", e);
                        e.printStackTrace();
                    }
                    out.flush();
                    out.close();
                    fileStream.close();
                    //使用公钥RSA加密AES的密钥
                    String digitalEnvelope = RSAUtil.encrypt(secretKey, publicKey);
                    logger.info(realFileName + " -- 保存文件信息到数据库");
                    //文件信息保存到数据库
                    FileInfo fileInfo = new FileInfo();
                    fileInfo.setName(realFileName);
                    fileInfo.setCreationTime(date);
                    fileInfo.setSize(size);
                    fileInfo.setType(type);
                    fileInfo.setOriginalName(fileName);
                    fileInfo.setDirectoryAddress(path);
                    fileInfo.setDigitalEnvelope(digitalEnvelope);
                    List<FileInfo> list = new ArrayList<>(1);
                    list.add(fileInfo);
                    FileInfoDao dao = new FileInfoDao();
                    dao.batchInsert(list);

                    resp.setContentType("text/html");
                    resp.setStatus(HttpServletResponse.SC_OK);
                    resp.getWriter().write(realFileName);
                }
            }
        } catch (FileUploadException e) {
            logger.error("文件上传失败", e);
            resp.setContentType("text/html");
            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }


    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}
